#pragma once

#include <map>
#include <vector>
#include <deque>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/map.hpp>

#include <arpa/inet.h>

#include "rapidxml.hpp"
#include "rapidxml_print.hpp"
#include "ExtXml.h"

using namespace boost::archive;

// ================================================================================

typedef uint32_t IPAddress;
typedef std::deque<IPAddress> Reachables;

// --------------------------------------------------------------------------------

struct Interface {
  IPAddress address;
  IPAddress netmask;

  Reachables reach;

  template<typename A>
  void serialize(A& ar, const unsigned int v) {
    ar & address;
    ar & netmask;
    ar & reach;
  }

  rapidxml::xml_node<>* serialize(net::ExtXml& xml) const {
    rapidxml::xml_node<>* ifNode = xml.allocate_node(rapidxml::node_element, "interface");
    ifNode->append_attribute(xml.allocate_attribute("address", xml.allocate_string(toString(address))));
    ifNode->append_attribute(xml.allocate_attribute("mask", xml.allocate_string(toString(netmask))));

    for (Reachables::const_iterator it = reach.begin();
         it != reach.end();
         ++it) {
      rapidxml::xml_node<>* netNode = xml.allocate_node(rapidxml::node_element, "node");
      netNode->append_attribute(xml.allocate_attribute("address", xml.allocate_string(toString(*it))));

      ifNode->append_node(netNode);
    }

    return ifNode;
  }
};

typedef std::map<unsigned int, Interface> Interfaces;

// --------------------------------------------------------------------------------

struct NetworkNode {
  bool router;
  Interfaces ifs;

  template<typename A>
  void serialize(A& ar, const unsigned int v) {
    ar & ifs;
  }

  void serialize(net::ExtXml& xml, rapidxml::xml_node<>* root) const {
    rapidxml::xml_node<>* router = xml.allocate_node(rapidxml::node_element, "router");

    for (Interfaces::const_iterator it = ifs.begin();
         it != ifs.end();
         ++it) {

      router->append_node(it->second.serialize(xml));
    }
    
    root->append_node(router);
  }
};

typedef std::deque<NetworkNode> Routers;

// --------------------------------------------------------------------------------

